/***************************************************************************
 *   Copyright (C) 2004 by cyril dupuit                                    *
 *   cyrildupuit@hotmail.com                                               *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

//*****************************************************************************
// Nom du module : Mount.c
// Description : Ce module est utilise pour gerer le system de fichiers virtuel
//*****************************************************************************
 
// Historique :
// 01/02/05 : TODO : Ajouter les codes d'erreurs a chaque retour de ERROR ou NULL 
// 24/01/05 : Creation du module V1.0

#include "Kernel/Types.h"
#include "Config.h"
#include "Arch/Arch.h"
#include "Kernel/Core.h"
#include "Kernel/Semaphor.h"
#include "Kernel/List.h"
#include "FileSys/vfs/Mount.h"
#include "FileSys/vfs/Vfs.h"
#include "Arch/Pentium/Kernel/malloc.h"
#include "Kernel/Errors.h"
#include "Lib/StdLib/string.h"
#include "Lib/LinkList.h"
#include "Lib/Stack.h"
#include "Lib/Queue.h"

//*****************************************************************************
// Variables externes :
//*****************************************************************************

extern struct VfsHead Vfs;

//*****************************************************************************
// Prototpes :
//*****************************************************************************

static void VfsMountDeleteTreeObjects(LinkListID_t MountList, StackID_t Stack);

static Status_t VfsGetDescriptor(char * pLocation, struct VfsMount * * pMnt);
static Status_t GetDirectory(char * pLocation, unsigned int * pI, char * pDir);
static Status_t VfsFindLocation(char * pDir, struct VfsMount * * pMnt);
static unsigned int VfsMountGetKey(char * pString);
static void VfsMountHashAdd(unsigned int Key, struct VfsMount * pNode);
static void VfsMountHashDelete(unsigned int Key, struct VfsMount * pNode);
static void VfsMountAddTree(struct VfsMount * pParent, struct VfsMount * pNode);
static void VfsMountDeleteTree(struct VfsMount * pParent, struct VfsMount * pNode);
static void VfsMountChangeFather(struct VfsMount * pMnt, struct VfsMount * pFather);
static void VfsMountGiveChild(struct VfsMount * pMnt);
static void VfsMountDeleteChild(struct VfsMount * pParent, struct VfsMount * pNode);

//*****************************************************************************
// Corps des fonctions/procedures
//*****************************************************************************

//*****************************************************************************
// But de la fonction : Initialiser la liste des descripteurs de montage
// Entree : Aucune
// Parametre retourne : TRUE
//*****************************************************************************
Status_t VfsMountInit(void)
{
	unsigned int Size;
	Status_t Status;
	
	ListInit(Vfs.pMntList);
	Vfs.MntCount = 0;
	Vfs.pMount = NULL;
	
	Size = MOUNT_HASH_TABLE_SIZE * sizeof(struct VfsMount *);
	
	Vfs.MountSem = SemMCreate(SEM_FIFO);
	if(Vfs.MountSem == 0) return ERROR;
	
	Vfs.pMntHash = (struct VfsMount * *)kmalloc(Size);
	if(Vfs.pMntHash == NULL)
	{//Memoire disponible insuffisante
		Status = SemDelete(&Vfs.MountSem);
		FatalErrorIf(Status != TRUE);
		return ERROR;
	}
	//Initialiser le tableau
	memset(Vfs.pMntHash, 0, Size);
	
	return TRUE;
}

//*****************************************************************************
// But de la fonction : Creer un descripteur de montage et retourner son
// descripteur
// Entree : 
//	pLocation : Pointeur sur l'emplacement
//	pName : Nom du systeme de fichiers
// Parametre retourne : NULL si descripteur non cree, pointeur sur le
// descripteur sinon
//*****************************************************************************
struct VfsMount * VfsMountCreate(char * pLocation, char * pName)
{
	struct VfsMount * pParent = NULL;
	struct VfsMount * pMnt;
	struct VfsMount * pTemp;
	unsigned int Key, Size;
	
	if((pLocation == NULL)||(pName == NULL))
	{//Parametre invalide
		return NULL;
	}
	
	Size = strlen(pName);
	
	if(Size >= MOUNT_NAME_MAX_SIZE)
	{//Nom de montage trop long
		return NULL;
	}
	
	pMnt = (struct VfsMount *)kmalloc(sizeof(struct VfsMount));
	if(pMnt == NULL)
	{//Memoire disponible insuffisante
		return NULL;
	}
	memset(pMnt, 0, sizeof(struct VfsMount));
	
	pMnt->pName = (char *)kmalloc(Size + 1);
	if(pMnt->pName == NULL)
	{//Memoire disponible insuffisante
		kfree(pMnt);
		return NULL;
	}
	
	strcpy(pMnt->pName, pName);
	
	//Prendre le semaphore de protection
	if(SemTake(Vfs.MountSem, SEM_WAIT_FOREVER) == ERROR)
	{//Erreur lors de la prise du semaphore
		FatalErrorIf(TRUE);
	}
	
	//Recuperer le descripteur de montage de l'emplacement
	if(VfsGetDescriptor(pLocation, &pParent) == ERROR)
	{//L'emplacement est incorrect
		if(SemGive(Vfs.MountSem) == ERROR)
		{//Erreur de gestion
			FatalErrorIf(TRUE);
		}
		kfree(pMnt->pName);
		kfree(pMnt);
		return NULL;
	}
	//verifier que le nom n'est pas deja present dans l'arborescence
	pTemp = pParent;
	if(VfsFindLocation(pName, &pTemp) == TRUE)
	{//Le repertoire est deja present
		if(SemGive(Vfs.MountSem) == ERROR)
		{//Erreur de gestion
			FatalErrorIf(TRUE);
		}
		kfree(pMnt->pName);
		kfree(pMnt);
		return NULL;
	}

	//Ajouter pMnt a l'arborescence
	VfsMountAddTree(pParent, pMnt);
	//Inserer le descripteur dans la table de hachage
	Key = VfsMountGetKey(pName);
	VfsMountHashAdd(Key, pMnt);
	//Inserer le descripteur dans la liste
	ListAddTail(Vfs.pMntList, pMnt);
	Vfs.MntCount++;
	
	if(SemGive(Vfs.MountSem) == ERROR)
	{//Erreur de gestion
		FatalErrorIf(TRUE);
	}
	
	return pMnt;
}

//*****************************************************************************
// But de la fonction : Supprimer un descripteur de montage en fonction de son
// chemin
// Entree : 
//	pLocation : Pointeur sur l'emplacement
//	pName : Nom du systeme de fichiers
// Parametre retourne : FALSE si le descripteur n'a pas ete supprime, TRUE
// sinon
//*****************************************************************************
Status_t VfsMountDelete(char * pLocation, char * pName)
{
	struct VfsMount * pParent = NULL;
	struct VfsMount * pMnt;
	unsigned int Key;
	
	if((pLocation == NULL)||(pName == NULL))
	{//Parametre invalide
		return ERROR;
	}
	
	//Prendre le semaphore de protection
	if(SemTake(Vfs.MountSem, SEM_WAIT_FOREVER) == ERROR)
	{//Erreur lors de la prise du semaphore
		FatalError(GetLastError(), "VfsMountDelete");
	}
	
	//Recuperer le descripteur de montage de l'emplacement
	if(VfsGetDescriptor(pLocation, &pParent) == ERROR)
	{//L'emplacement est incorrect
		if(SemGive(Vfs.MountSem) == ERROR)
		{//Erreur de gestion
			FatalError(GetLastError(), "VfsMountDelete");
		}
		return ERROR;
	}
	//Obtenir le descripteur associe
	pMnt = pParent;
	if(VfsFindLocation(pName, &pMnt) == FALSE)
	{//Le repertoire n'existe pas
		if(SemGive(Vfs.MountSem) == ERROR)
		{//Erreur de gestion
			FatalError(GetLastError(), "VfsMountDelete");
		}
		return ERROR;
	}
	if(pMnt->MntCount > 0)
	{//Des sous repertoires existes
		if(SemGive(Vfs.MountSem) == ERROR)
		{//Erreur de gestion
			FatalError(GetLastError(), "VfsMountDelete");
		}
		return FALSE;
	}
	
	//Ajouter pMnt a l'arborescence
	VfsMountDeleteTree(pParent, pMnt);
	
	//Inserer le descripteur dans la table de hachage
	Key = VfsMountGetKey(pName);
	VfsMountHashDelete(Key, pMnt);
	
	//Supprimer le descripteur dans la liste
	ListDelete(Vfs.pMntList, pMnt);
	
	Vfs.MntCount--;
	
	if(SemGive(Vfs.MountSem) == ERROR)
	{//Erreur de gestion
		FatalError(GetLastError(), "VfsMountDelete");
	}
	
	return TRUE;
}

//*****************************************************************************
// But de la fonction : Retourner le nombre de systemes de fichiers montes
// Entree : Aucune
// Parametre retourne : Nombre de systemes de fichiers montes
//*****************************************************************************
Count_t VfsMountCount(void)
{
	Count_t Count;
	
	//Prendre le semaphore de protection
	if(SemTake(Vfs.MountSem, SEM_WAIT_FOREVER) == ERROR)
	{//Erreur lors de la prise du semaphore
		FatalError(GetLastError(), "VfsMountCount");
	}
	
	Count = Vfs.MntCount;
	
	if(SemGive(Vfs.MountSem) == ERROR)
	{//Erreur de gestion
		FatalError(GetLastError(), "VfsMountCount");
	}
	
	return Count;
}

//*****************************************************************************
// But de la fonction : Dresser une liste des systemes crees. Cette liste est
// rangee dans une file d'attente fournie en parametre
// Entree :
//	QueueID : Numero d'identification de la file d'attente
// Parametre retourne : ERROR si le numero d'identification de la file
// d'attente est incorrect, FALSE si la file d'attente est trop petite, TRUE
// sinon
//*****************************************************************************
Status_t VfsMountGetList(QueueID_t QueueID)
{
	int Count;
	struct VfsMount * pNode;
	Queue_t * pQueue = (Queue_t *)QueueID;
	
	if((QueueID == 0)||(pQueue->QueueID != QueueID)) return ERROR;
	
	if(SemTake(Vfs.MountSem, SEM_WAIT_FOREVER) == ERROR)
	{//Erreur lors de la prise du semaphore
		FatalError(GetLastError(), "VfsMountGetList");
	}
	
	ListForeach(Vfs.pMntList, pNode, Count)
	{//Explorer la liste des processus
		if(QueueWrite(QueueID, (Object_t *)pNode, 1) == FALSE)
		{//Si plus de place disponible, retourner FALSE
			if(SemGive(Vfs.MountSem) == ERROR)
			{//Erreur de gestion
				FatalError(GetLastError(), "VfsMountGetList");
			}
			return FALSE;
		}
	}
	
	if(SemGive(Vfs.MountSem) == ERROR)
	{//Erreur de gestion
		FatalError(GetLastError(), "VfsMountGetList");
	}
	
	return TRUE;
} 

//*****************************************************************************
// But de la fonction : Dresser un arbre des systemes de fichiers crees.
// Entree : Aucune
// Parametre retourne : 0 si memoire insuffisante, identificateur de la liste
// chaine
//*****************************************************************************
LinkListID_t VfsMountGetTree(void)
{
	struct VfsMount * pParent;
	struct VfsMount * pChild;
	unsigned int Level = 0;
	VfsMountTree_t * pTree;
	LinkListID_t MountList, Stack = 0;
	unsigned int Size;
	
	MountList = LinkListCreate();
	if(MountList == 0)
	{//Memoire insuffisante
		return 0;
	}

	Stack = StackCreate(2 * Vfs.MntCount);
	if(Stack == 0)
	{//Memoire insuffisante
		LinkListDelete(&MountList);
		return 0;
	}
	
	if(SemTake(Vfs.MountSem, SEM_WAIT_FOREVER) == ERROR)
	{//Erreur lors de la prise du semaphore
		FatalError(GetLastError(), "VfsMountGetTree");
	}
	
	pParent = Vfs.pMount;//Systeme racine
	if(StackPush(Stack, (Cell_t)pParent) == ERROR)
	{//Memoire insuffisante pour empiler le descripteur de tache
		VfsMountDeleteTreeObjects(MountList, Stack);
		return 0;
	}
	if(StackPush(Stack, (Cell_t)Level) == ERROR)
	{//Memoire insuffisante pour empiler le niveau
		VfsMountDeleteTreeObjects(MountList, Stack);
		return 0;
	}
	while(StackCount(Stack) > 0)
	{
		if(StackPop(Stack, (Cell_t *)&Level) == FALSE)//Depiler le niveau
		{//Pile trop petite
			VfsMountDeleteTreeObjects(MountList, Stack);
			return 0;
		}
		if(StackPop(Stack, (Cell_t *)&pParent) == FALSE)//Depiler le descripteur de tache
		{//Pile trop petite
			VfsMountDeleteTreeObjects(MountList, Stack);
			return 0;
		}
		//Noter les informations relative a ce descipteur de montage
		pTree = (VfsMountTree_t *)kmalloc(sizeof(VfsMountTree_t));
		if(pTree == 0) 
		{//Memoire insuffisante
			VfsMountDeleteTreeObjects(MountList, Stack);
			return 0;
		}
		Size = strlen(pParent->pName) + 1; // + 1 => '\0'
		pTree->pName = (char *)kmalloc(Size * sizeof(char));
		if(pTree->pName == NULL)
		{//Memoire insuffisante
			VfsMountDeleteTreeObjects(MountList, Stack);
			return 0;
		}
		strcpy(pTree->pName, pParent->pName);
		pTree->Level = Level;
		pTree->Status = 0;
		pTree->pMnt = pParent;

		if(LinkListAddTail(MountList, pTree) == NULL)
		{//Memoire insuffisante
			VfsMountDeleteTreeObjects(MountList, Stack);
			return 0;
		}
		
		if(pParent->Mnt.pNext != NULL)
		{//Empiler la soeur droite
			Set(pTree->Status, MOUNT_BROTHER_PRESENT);
			if(StackPush(Stack, (Cell_t)pParent->Mnt.pNext) == FALSE)
			{//Pile trop petite
				VfsMountDeleteTreeObjects(MountList, Stack);
				return 0;
			}
			if(StackPush(Stack, (Cell_t)Level) == FALSE)
			{//Pile trop petite
				VfsMountDeleteTreeObjects(MountList, Stack);
				return 0;
			}
		}
		pChild = pParent->pFirstChild;
		if(pChild != NULL)
		{//Empiler la plus vieille fille
			Level++;
			Set(pTree->Status, MOUNT_CHILD_PRESENT);
			if(StackPush(Stack, (Cell_t)pChild) == ERROR)
			{//Memoire insuffisante
				VfsMountDeleteTreeObjects(MountList, Stack);
				return 0;
			}
			if(StackPush(Stack, (Cell_t)Level) == ERROR)
			{//Memoire insuffisante
				VfsMountDeleteTreeObjects(MountList, Stack);
				return 0;
			}
		}
	}

	if(SemGive(Vfs.MountSem) == ERROR)
	{//Erreur de gestion
		FatalError(GetLastError(), "VfsMountGetList");
	}
	
	StackDelete(&Stack);

	return MountList;
}

//*****************************************************************************
// But de la procedure : Supprimer les objets utilises lors de la creation 
// de l'arbre des systemes de fichiers
// Enttrees :
//	MountList : Liste des threads
//	Stack : Pile
// Sortie : Aucune
//*****************************************************************************
static void VfsMountDeleteTreeObjects(LinkListID_t MountList, StackID_t Stack)
{
	VfsMountTree_t * pTree;
	
	if(SemGive(Vfs.MountSem) == ERROR)
	{//Erreur de gestion
		FatalError(GetLastError(), "VfsMountDeleteTreeObjects");
	}
	
	StackDelete(&Stack);
	
	pTree = LinkListRemoveTail(MountList);
	while(pTree != NULL)
	{
		if(pTree->pName != NULL) kfree(pTree->pName);
		if(pTree != NULL) kfree(pTree);
		pTree = LinkListRemoveTail(MountList);
	}

	LinkListDelete(&MountList);
}

//*****************************************************************************
// But de la fonction : Recuperer le descripteur de montage d'un emplacement
// Entree :
//	pLocation : Emplacement sous forme de chaine de caractere
// Sortie :
//	pMnt : Descripteur de montage correspondant
// Parametre retourne : ERROR si un des parametres est invalide, FALSE si
// chemin non trouve, TRUE sinon
//*****************************************************************************
static Status_t VfsGetDescriptor(char * pLocation, struct VfsMount * * pMnt)
{
	struct VfsMount * pNode = *pMnt;
	char Buffer[MOUNT_NAME_MAX_SIZE + 1];
	unsigned int I = 0;
	
	if(Vfs.MntCount == 0)
	{//Aucun repertoire
		*pMnt = NULL;
		return TRUE;
	}
	
	while(*pLocation == '/') pLocation++;//Eviter le slash de depart
	
	while(pLocation[I] != '\0')
	{//Explorer l'arbre
		if(pLocation[I] == '/')
		{//Eviter le slash
			I++;
		}
		else
		{//Recuperer le repertoire
			GetDirectory(pLocation, &I, Buffer);
			//Obtenir le descripteur associe
			if(VfsFindLocation(Buffer, &pNode) == FALSE)
			{//Emplacement non trouve
				return FALSE;
			}
		}
	}
	
	*pMnt = pNode;
	
	return TRUE;
}

//*****************************************************************************
// But de la fonction : Extraire un nom de repertoire
// Entrees :
//	pLocation : Emplacement
//	pI : Pointeur sur l'index de l'emplacement
// Sorties :
//	pI : Pointeur sur l'index de l'emplacement
//	pDir : Pointeur sur le repertoire extrait
// Parametre retourne : FALSE si la chaine est incorrect, TRUE sinon
//*****************************************************************************
static Status_t GetDirectory(char * pLocation, unsigned int * pI, char * pDir)
{
	unsigned int I;
	
	for(I = *pI; pLocation[I] != '\0'; I++)
	{//Explorer l'emplacement
		if(pLocation[I] == '/')
		{//Slash rencontre
			*pDir++ = '\0';//Terminer le nom de repertoire
			*pI = I;
			return TRUE;
		}
		else 
		{
			*pDir++ = pLocation[I];
		}
	}
	
	*pDir++ = '\0';//Terminer le nom de repertoire
	*pI = I;
	
	return TRUE;
}

//*****************************************************************************
// But de la fonction : Trouver un descripteur de montage en fonction de son
// nom et de son pere
// Entrees :
//	pDir : Nom du repertoire sous forme de chaine de caractere
//	pMnt : Pointeur sur le repertoire parent
// Sortie :
//	pMnt : Pointeur sur le descripteur de montage
// Parametre retourne : FALSE si le descripteur n'a pas ete trouve, TRUE sinon
//*****************************************************************************
static Status_t VfsFindLocation(char * pDir, struct VfsMount * * pMnt)
{
	struct VfsMount * pNode;
	unsigned int Count;
	unsigned int Key = 0;
	unsigned int Size = strlen(pDir);
	
	if(Size == 0) return TRUE;
	
	if(pDir[0] == '.') 
	{//Suivre les entrees . et ..
		switch (Size)
		{
			default:
				break;
			case 2:
				if(pDir[1] != '.') break;
				if((*pMnt)->pParent != NULL)
				{//Obtenir le pere de *pMnt
					*pMnt = (*pMnt)->pParent;
					return TRUE;
				}
				return FALSE;
			case 1:
				*pMnt = *pMnt;
				return TRUE;
		}
	}
	
	Key = VfsMountGetKey(pDir);
	
	for(Count=0, pNode = Vfs.pMntHash[Key]; \
            (pNode != NULL)&&(!Count || (pNode != Vfs.pMntHash[Key])); \
            Count++, pNode = pNode->Hash.pNext)
	{//Explorer ce niveau
		if(strcmp(pDir, pNode->pName) == 0)
		{//Comparer la chaine affin d'eviter les problemes de collision
			if(pNode->pParent == *pMnt)
			{//Les parents correspondent
				*pMnt = pNode;
				return TRUE;
			}
		}
	}
	
	return FALSE;
}

//*****************************************************************************
// But de la fonction : Calculer la clef de la table de hachage de la chaine
// de caractere
// Entree : 
//	pString : Pointeur sur la chaine de caractere
// Parametre retourne : Valeur de la clef
//*****************************************************************************
static unsigned int VfsMountGetKey(char * pString)
{
	unsigned int I, Key;
	
	for(Key = 0, I = 0; pString[I] != '\0'; I++)
	{
		Key += pString[I];
	}
	
	return Key % MOUNT_HASH_TABLE_SIZE;
}

//*****************************************************************************
// But de la procedure : Ajouter une entree dans la table de hachage
// Entrees :
//	Key : Entree de la table de hachage
//	pNode : Pointeur sur le descripteur a inserer
// Sortie : Aucune
//*****************************************************************************
static void VfsMountHashAdd(unsigned int Key, struct VfsMount * pNode) 
{
	struct VfsMount * pList = Vfs.pMntHash[Key];
	
	if(pList != NULL) 
	{
		pList->Hash.pPrev->Hash.pNext = pNode;
		pNode->Hash.pPrev = pList->Hash.pPrev;
		pList->Hash.pPrev = pNode;
		pNode->Hash.pNext = pList;
	}
	else
	{
		pNode->Hash.pNext = pNode;
		pNode->Hash.pPrev = pNode;
		Vfs.pMntHash[Key] = pNode;
	}
}

//*****************************************************************************
// But de la procedure : Supprimer une entree de la table de hachage
// Entrees : 
//	Key : Entree de la table de hachage
//	pNode : Pointeur sur le descripteur a supprimer
// Sortie : Aucune
//*****************************************************************************
static void VfsMountHashDelete(unsigned int Key, struct VfsMount * pNode)
{
	if((pNode->Hash.pNext == pNode)&&(pNode->Hash.pPrev == pNode))
	{
		Vfs.pMntHash[Key] = NULL;
	}
	else
	{
		pNode->Hash.pPrev->Hash.pNext = pNode->Hash.pNext; 
		pNode->Hash.pNext->Hash.pPrev = pNode->Hash.pPrev; 
		if(pNode == Vfs.pMntHash[Key]) Vfs.pMntHash[Key] = pNode->Hash.pNext;
	}
	pNode->Hash.pNext = NULL;
	pNode->Hash.pPrev = NULL;
}

//*****************************************************************************
// But de la procedure : Ajouter un descripteur en queue de la liste du pere
// Entrees :
//	pParent : Pointeur sur la liste
//	pNode : Pointeur sur le descripteur a inserer
// Sortie : Aucune
//*****************************************************************************
static void VfsMountAddTree(struct VfsMount * pParent, struct VfsMount * pNode) 
{
	struct VfsMount * pPrev;
	struct VfsMount * pNext;
	
	if(pParent == NULL)
	{
		if(Vfs.pMount == NULL) 
		{//Premier element de l'arbre
			Vfs.pMount = pNode;
			return;
		}
		else
		{
			pNext = Vfs.pMount->Mnt.pNext;
			if(pNext != NULL) pNext->Mnt.pPrev = pNode;
			pNode->Mnt.pNext = pNext;
			Vfs.pMount->Mnt.pNext = pNode;
			pNode->Mnt.pPrev = Vfs.pMount;
			return;
		}
	}
	else if(pParent->pFirstChild == NULL) 
	{
		pNode->Mnt.pNext = NULL;
		pNode->Mnt.pPrev = NULL;
		pParent->pFirstChild = pNode;
		pParent->pLastChild = pNode;
	}
	else
	{
		pPrev = pParent->pLastChild;
		pParent->pLastChild = pNode;
		pNode->Mnt.pNext = NULL;
		pNode->Mnt.pPrev = pPrev;
		pPrev->Mnt.pNext = pNode;
	}
	
	//Ajout du pere
	pNode->pParent = pParent;
	//Incrementer le nombre d'enfants du pere
	pParent->MntCount++;
}

//*****************************************************************************
// But de la procedure: : Supprimer un descripteur
// Entree : 
//	pParent : Pointeur sur le pere
//	pNode : Pointeur sur le descripteur a supprimer
// Sortie : Aucune
//*****************************************************************************
static void VfsMountDeleteTree(struct VfsMount * pParent, struct VfsMount * pNode)
{
	struct VfsMount * pPrev = pNode->Mnt.pPrev;
	struct VfsMount * pNext = pNode->Mnt.pNext;
	
	if(pParent == NULL) 
	{//Le pere n'existe pas
		if(pNext != NULL) pNext->Mnt.pPrev = pPrev;
		if(pPrev != NULL) pPrev->Mnt.pNext = pNext;
		if(Vfs.pMount == pNode) Vfs.pMount = pNext;
	}
	else
	{
		//Affecter le pere de pNode aux enfants de pNode
		VfsMountChangeFather(pNode, pParent);
		//Donner les enfants de pNode au pere de pNode
		VfsMountGiveChild(pNode);
		//supprimer pNode
		VfsMountDeleteChild(pParent, pNode);
		
		pParent->MntCount--;
	}
	
	//Detruire les liens
	pNode->pParent = NULL;
	pNode->pFirstChild = NULL;
	pNode->pLastChild = NULL;
	pNode->Mnt.pPrev = NULL;
	pNode->Mnt.pNext = NULL;
}

//*****************************************************************************
// But de la procedure : Changer le pere de la liste des enfants
// Entrees : 
//	pMnt : Pointeur sur la liste des enfants
//	pFather : Pointeur sur le nouveau pere
// Sortie : Aucune
//*****************************************************************************
static void VfsMountChangeFather(struct VfsMount * pMnt, struct VfsMount * pFather)
{
	struct VfsMount * pNode;
	
	pNode = pMnt->pFirstChild;
	while(pNode != NULL)
	{
		pNode->pParent = pFather;
		pNode = pNode->Mnt.pNext;
	}
}

//*****************************************************************************
// But de la procedure : Affecter les enfants de pMnt a son pere pFather
// Entrees : 
//	pMnt : Pointeur sur le descripteur qui doit donner ses enfants
// Sortie : Aucune
//*****************************************************************************
static void VfsMountGiveChild(struct VfsMount * pMnt)
{
	struct VfsMount * pNode;
	struct VfsMount * pFather = pMnt->pParent;
	
	pNode = pMnt->pFirstChild;
	while(pNode != NULL)
	{
		VfsMountDeleteChild(pMnt, pNode);
		VfsMountAddTree(pFather, pNode);
		pNode = pMnt->pFirstChild;
	}
}

//*****************************************************************************
// But de la procedure : Supprimer un enfant de la liste
// Entrees : 
//	pParent : Liste des enfants
//	pNode : Pointeur sur l'enfant a retirer
// Sortie : Aucune
//*****************************************************************************
static void VfsMountDeleteChild(struct VfsMount * pParent, struct VfsMount * pNode)
{
	struct VfsMount * pPrev = pNode->Mnt.pPrev;
	struct VfsMount * pNext = pNode->Mnt.pNext;
	
	if(pParent->pFirstChild == pParent->pLastChild)
	{//La liste contient un element
		pParent->pFirstChild = NULL;
		pParent->pLastChild = NULL;
	}
	else
	{
		if(pNode == pParent->pFirstChild) pParent->pFirstChild = pNode->Mnt.pNext;
		if(pNode == pParent->pLastChild) pParent->pLastChild = pNode->Mnt.pPrev;
		
		if(pNext != NULL) pNext->Mnt.pPrev = pPrev;
		if(pPrev != NULL) pPrev->Mnt.pNext = pNext;
	}
	
	pNode->Mnt.pNext = NULL;
	pNode->Mnt.pPrev = NULL;
}

//*****************************************************************************
